package com.project.quiktask.google;

import java.io.File;
import java.io.IOException;
import java.text.ParseException;
import java.util.Arrays;
import java.util.Scanner;
import java.util.Vector;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.FileCredentialStore;
import com.google.api.client.googleapis.GoogleHeaders;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeRequestUrl;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.auth.oauth2.GoogleTokenResponse;
import com.google.api.client.googleapis.batch.BatchRequest;
import com.google.api.client.googleapis.batch.json.JsonBatchCallback;
import com.google.api.client.googleapis.json.GoogleJsonError;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson.JacksonFactory;
import com.google.api.client.util.DateTime;
import com.google.api.services.calendar.model.Calendar;
import com.google.api.services.calendar.model.CalendarList;
import com.google.api.services.calendar.model.CalendarListEntry;
import com.google.api.services.calendar.model.Event;
import com.google.api.services.calendar.model.EventDateTime;
import com.project.quiktask.Task;
import com.project.quiktask.datastore.FileLoader;
import com.project.quiktask.util.Variable;

/**
 * @author Guo Jing
 * 
 *         Known Issues: 1) Credentials not stored in a CredentialStore due to
 *         bug in Google API that is pending fix 2) User cannot select calendar
 *         to synchronise to; calendar named "QuikTask" is used 3) GoogleCal
 *         works independently of the other components for now 4) Unable to add
 *         more than one Event to calendar
 */
public class GoogleCal {
	private HttpTransport HTTP_TRANSPORT;
	private JsonFactory JSON_FACTORY;
	private static String clientId;
	private static String clientSecret;
	private static String redirectUri;
	private static Iterable<String> scope;
	private GoogleAuthorizationCodeFlow myFlow;
	private static com.google.api.services.calendar.Calendar client;

	public GoogleCal() {
		HTTP_TRANSPORT = new NetHttpTransport();
		JSON_FACTORY = new JacksonFactory();
		clientId = "311705253708.apps.googleusercontent.com";
		clientSecret = "EXn0nHUen5-FJZKwDSFvswS7";
		scope = Arrays.asList("https://www.googleapis.com/auth/calendar",
				"https://www.googleapis.com/auth/tasks");
		redirectUri = "urn:ietf:wg:oauth:2.0:oob";

		myFlow = new GoogleAuthorizationCodeFlow.Builder(HTTP_TRANSPORT,
				JSON_FACTORY, clientId, clientSecret, scope)
				.setAccessType("offline").setApprovalPrompt("auto").build();

	}

	public void run() throws IOException {

		// Check for existing user Google credential
		GoogleCredential credential = null;
		credential = null;

		// Creates new credential if credential is not found earlier
		if (credential == null) {
			try {
				credential = authorize();
				// credentialStore.store("user", credential);
			} catch (Exception e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}

		// set up global Calendar instance
		client = new com.google.api.services.calendar.Calendar.Builder(
				HTTP_TRANSPORT, JSON_FACTORY, credential).build();

		// run commands

		CalendarList allCalendars = client.calendarList().list().execute();

		String calendarId = null;
		String temp;

		for (CalendarListEntry entry : allCalendars.getItems()) {
			temp = entry.getSummary();
			if (temp.equals("QuikTask")) {
				calendarId = entry.getId();
				break;
			}
		}

		if (calendarId == null)
			calendarId = addCalendar().getId();

		client.calendars().clear(calendarId);

		FileLoader fileLoader = new FileLoader(Variable.STORAGE_FILE_NAME);

		Vector<Task> tasksToAdd = null;

		try {
			tasksToAdd = fileLoader.load();
		} catch (ParseException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		BatchRequest batchRequest = client.batch();

		JsonBatchCallback<Event> callback = new JsonBatchCallback<Event>() {

			@Override
			public void onSuccess(Event arg0, GoogleHeaders arg1) {
				// TODO Auto-generated method stub

			}

			@Override
			public void onFailure(GoogleJsonError arg0, GoogleHeaders arg1)
					throws IOException {
				// TODO Auto-generated method stub

			}

		};

		for (Task task : tasksToAdd) {
			if (task.getStartDate() != null) {
				Event entry = new Event();

				entry.setSummary(task.getTaskDescription());

				if (task.getDeadlineDate() != null)
					entry.setDescription("This task is due"
							+ task.getDeadlineTime() + "on"
							+ task.getDeadlineDate());

				System.out.println(task.getStartDate() + "T"
						+ task.getStartTime() + "Z");

				entry.setStart(new EventDateTime().setDateTime(new DateTime(
						task.getStartDate() + "T" + task.getStartTime() + "Z")));

				System.out.println(entry.getStart());

				entry.setEnd(new EventDateTime().setDateTime(new DateTime(task
						.getEndDate() + "T" + task.getEndTime() + "Z")));

				client.events().insert(calendarId, entry)
						.queue(batchRequest, callback);

			}

			batchRequest.execute();

		}

	}

	private static void showCalendars() throws IOException {
		View.header("Show Calendars");
		CalendarList feed = client.calendarList().list().execute();
		View.display(feed);
	}

	private static Calendar addCalendar() throws IOException {
		View.header("Add Calendar");
		Calendar entry = new Calendar();
		entry.setSummary("QuikTask");
		Calendar result = client.calendars().insert(entry).execute();
		View.display(result);
		return result;
	}

	private GoogleCredential authorize() throws IOException {

		// create URL to google authentication
		GoogleAuthorizationCodeRequestUrl URL = myFlow.newAuthorizationUrl()
				.setRedirectUri(redirectUri);

		// give user URL
		System.out.println(URL);

		// get authorisation code from user
		String authCode = null;
		authCode = (new Scanner(System.in)).nextLine();

		GoogleTokenResponse response = null;
		try {
			response = myFlow.newTokenRequest(authCode)
					.setRedirectUri(redirectUri).execute();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}

		return (new GoogleCredential()
				.setAccessToken(response.getAccessToken()));
	}
}
